﻿#region

using System;
using System.Globalization;
using System.Linq.Expressions;
using Telerik.Windows.Controls;
using Telerik.Windows.Data;

#endregion

namespace Rio.Framework.Pages.Workflow
{
    public class StateFilterDescriptor : FilterDescriptorBase
    {
        #region Readonly & Static Fields

        private static readonly ConstantExpression TrueExpression = Expression.Constant(true);
        private readonly CompositeFilterDescriptor compositeFilterDesriptor;

        #endregion

        #region Fields

        private string _filterValue;

        #endregion

        #region Constructors

        /// <summary>
        ///   Initializes a new instance of the <see cref="StateFilterDescriptor" /> class.
        /// </summary>
        /// <param name="column"> The column. </param>
        public StateFilterDescriptor(GridViewDataColumn column)
        {
            compositeFilterDesriptor = new CompositeFilterDescriptor();
            compositeFilterDesriptor.LogicalOperator = FilterCompositionLogicalOperator.Or;
            compositeFilterDesriptor.FilterDescriptors.Add(CreateFilterForColumn(column));
        }

        #endregion

        #region Instance Properties

        /// <summary>
        ///   Gets or sets the state value.
        /// </summary>
        /// <value> The state value. </value>
        public string FilterValue
        {
            get
            {
                return _filterValue;
            }
            set
            {
                if (_filterValue != value)
                {
                    _filterValue = value;
                    UpdateCompositeFilterValues();
                    OnPropertyChanged("FilterValue");
                }
            }
        }

        #endregion

        #region Instance Methods

        /// <summary>
        ///   Creates the filter expression.
        /// </summary>
        /// <param name="parameterExpression"> The parameter expression. </param>
        /// <returns> </returns>
        protected override Expression CreateFilterExpression(ParameterExpression parameterExpression)
        {
            if (string.IsNullOrEmpty(FilterValue))
            {
                return TrueExpression;
            }
            try
            {
                return compositeFilterDesriptor.CreateFilterExpression(parameterExpression);
            }
            catch
            {
            }

            return TrueExpression;
        }

        /// <summary>
        ///   Creates the filter for column.
        /// </summary>
        /// <param name="column"> The column. </param>
        /// <returns> </returns>
        private IFilterDescriptor CreateFilterForColumn(GridViewDataColumn column)
        {
            FilterOperator filterOperator = GetFilterOperatorForType(column.DataType);
            FilterDescriptor descriptor = new FilterDescriptor(column.UniqueName, filterOperator, _filterValue);
            descriptor.MemberType = column.DataType;

            return descriptor;
        }

        /// <summary>
        ///   Updates the composite filter values.
        /// </summary>
        private void UpdateCompositeFilterValues()
        {
            foreach (FilterDescriptor descriptor in compositeFilterDesriptor.FilterDescriptors)
            {
                object convertedValue = DefaultValue(descriptor.MemberType);

                try
                {
                    convertedValue = Convert.ChangeType(FilterValue, descriptor.MemberType, CultureInfo.CurrentCulture);
                }
                catch
                {
                }

                if (descriptor.MemberType.IsAssignableFrom(typeof (DateTime)))
                {
                    DateTime date;
                    if (DateTime.TryParse(FilterValue, out date))
                    {
                        convertedValue = date;
                    }
                }

                descriptor.Value = convertedValue;
            }
        }

        #endregion

        #region Class Methods

        /// <summary>
        ///   Defaults the value.
        /// </summary>
        /// <param name="type"> The type. </param>
        /// <returns> </returns>
        private static object DefaultValue(Type type)
        {
            if (type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }

            return null;
        }

        /// <summary>
        ///   Gets the type of the filter operator for.
        /// </summary>
        /// <param name="dataType"> Type of the data. </param>
        /// <returns> </returns>
        private static FilterOperator GetFilterOperatorForType(Type dataType)
        {
            return dataType == typeof (string) ? FilterOperator.Contains : FilterOperator.IsEqualTo;
        }

        #endregion
    }
}